<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSON格式化工具</title>
    <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/theme/monokai.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/javascript/javascript.min.js"></script>
</head>
<body class="bg-gray-50 min-h-screen">
    <div class="container mx-auto px-6 py-8">
        <div class="max-w-7xl mx-auto">
            <!-- 标题 -->
            <div class="text-center mb-8">
                <h1 class="text-3xl font-bold text-gray-800 mb-2">
                    <i class="fas fa-code text-purple-500 mr-2"></i>
                    JSON格式化工具
                </h1>
                <p class="text-gray-600">美化、压缩、验证和转换JSON数据</p>
            </div>
            
            <!-- 工具栏 -->
            <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4 mb-6">
                <div class="flex flex-wrap gap-4 items-center justify-between">
                    <div class="flex flex-wrap gap-2">
                        <button onclick="formatJSON()" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors">
                            <i class="fas fa-magic mr-2"></i>格式化
                        </button>
                        <button onclick="compressJSON()" class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition-colors">
                            <i class="fas fa-compress mr-2"></i>压缩
                        </button>
                        <button onclick="validateJSON()" class="bg-yellow-600 text-white px-4 py-2 rounded-lg hover:bg-yellow-700 transition-colors">
                            <i class="fas fa-check-circle mr-2"></i>验证
                        </button>
                        <button onclick="clearAll()" class="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700 transition-colors">
                            <i class="fas fa-trash mr-2"></i>清空
                        </button>
                    </div>
                    
                    <div class="flex gap-2">
                        <button onclick="copyToClipboard()" class="bg-gray-600 text-white px-4 py-2 rounded-lg hover:bg-gray-700 transition-colors">
                            <i class="fas fa-copy mr-2"></i>复制
                        </button>
                        <button onclick="downloadJSON()" class="bg-purple-600 text-white px-4 py-2 rounded-lg hover:bg-purple-700 transition-colors">
                            <i class="fas fa-download mr-2"></i>下载
                        </button>
                    </div>
                </div>
            </div>
            
            <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
                <!-- 输入区域 -->
                <div class="bg-white rounded-lg shadow-sm border border-gray-200">
                    <div class="border-b border-gray-200 p-4">
                        <div class="flex justify-between items-center">
                            <h3 class="text-lg font-semibold text-gray-800">输入JSON</h3>
                            <div class="flex gap-2">
                                <button onclick="loadSample()" class="text-sm bg-blue-100 text-blue-700 px-3 py-1 rounded hover:bg-blue-200 transition-colors">
                                    <i class="fas fa-file-import mr-1"></i>示例
                                </button>
                                <input type="file" id="fileInput" accept=".json" class="hidden">
                                <button onclick="document.getElementById('fileInput').click()" class="text-sm bg-green-100 text-green-700 px-3 py-1 rounded hover:bg-green-200 transition-colors">
                                    <i class="fas fa-upload mr-1"></i>上传
                                </button>
                            </div>
                        </div>
                    </div>
                    <div class="p-4">
                        <textarea id="inputJSON" placeholder="在此输入或粘贴JSON数据..." 
                                  class="w-full h-96 border border-gray-300 rounded-lg p-3 font-mono text-sm resize-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"></textarea>
                    </div>
                </div>
                
                <!-- 输出区域 -->
                <div class="bg-white rounded-lg shadow-sm border border-gray-200">
                    <div class="border-b border-gray-200 p-4">
                        <div class="flex justify-between items-center">
                            <h3 class="text-lg font-semibold text-gray-800">格式化结果</h3>
                            <div class="flex items-center gap-4">
                                <div id="statusIndicator" class="flex items-center">
                                    <div class="w-3 h-3 bg-gray-400 rounded-full mr-2"></div>
                                    <span class="text-sm text-gray-600">等待输入</span>
                                </div>
                                <select id="indentSize" class="text-sm border border-gray-300 rounded px-2 py-1">
                                    <option value="2">2空格</option>
                                    <option value="4" selected>4空格</option>
                                    <option value="\t">Tab</option>
                                </select>
                            </div>
                        </div>
                    </div>
                    <div class="p-4">
                        <div id="outputJSON" class="w-full h-96 border border-gray-300 rounded-lg overflow-auto"></div>
                    </div>
                </div>
            </div>
            
            <!-- 统计信息 -->
            <div class="mt-6 grid grid-cols-1 md:grid-cols-4 gap-4">
                <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4 text-center">
                    <div class="text-2xl font-bold text-blue-600" id="charCount">0</div>
                    <div class="text-sm text-gray-600">字符数</div>
                </div>
                <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4 text-center">
                    <div class="text-2xl font-bold text-green-600" id="lineCount">0</div>
                    <div class="text-sm text-gray-600">行数</div>
                </div>
                <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4 text-center">
                    <div class="text-2xl font-bold text-purple-600" id="sizeInfo">0 B</div>
                    <div class="text-sm text-gray-600">大小</div>
                </div>
                <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4 text-center">
                    <div class="text-2xl font-bold text-yellow-600" id="depthInfo">0</div>
                    <div class="text-sm text-gray-600">嵌套深度</div>
                </div>
            </div>
            
            <!-- 错误信息 -->
            <div id="errorPanel" class="mt-6 bg-red-50 border border-red-200 rounded-lg p-4" style="display: none;">
                <div class="flex items-start">
                    <i class="fas fa-exclamation-triangle text-red-500 mt-1 mr-3"></i>
                    <div>
                        <h4 class="text-red-800 font-semibold mb-2">JSON格式错误</h4>
                        <p id="errorMessage" class="text-red-700 text-sm"></p>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    <script>
        let inputEditor, outputEditor;
        
        // 初始化CodeMirror编辑器
        document.addEventListener('DOMContentLoaded', function() {
            // 输入编辑器
            inputEditor = CodeMirror.fromTextArea(document.getElementById('inputJSON'), {
                mode: 'application/json',
                theme: 'default',
                lineNumbers: true,
                lineWrapping: true,
                autoCloseBrackets: true,
                matchBrackets: true,
                indentUnit: 4,
                tabSize: 4
            });
            
            // 输出编辑器
            const outputContainer = document.getElementById('outputJSON');
            const outputTextarea = document.createElement('textarea');
            outputContainer.appendChild(outputTextarea);
            
            outputEditor = CodeMirror.fromTextArea(outputTextarea, {
                mode: 'application/json',
                theme: 'default',
                lineNumbers: true,
                lineWrapping: true,
                readOnly: true,
                indentUnit: 4,
                tabSize: 4
            });
            
            // 监听输入变化
            inputEditor.on('change', function() {
                updateStatistics();
                autoValidate();
            });
            
            // 文件上传处理
            document.getElementById('fileInput').addEventListener('change', handleFileUpload);
        });
        
        function formatJSON() {
            const input = inputEditor.getValue().trim();
            if (!input) {
                showError('请输入JSON数据');
                return;
            }
            
            try {
                const parsed = JSON.parse(input);
                const indentSize = document.getElementById('indentSize').value;
                const indent = indentSize === '\t' ? '\t' : parseInt(indentSize);
                const formatted = JSON.stringify(parsed, null, indent);
                
                outputEditor.setValue(formatted);
                showSuccess('JSON格式化成功');
                hideError();
                updateStatistics();
            } catch (error) {
                showError('JSON格式错误: ' + error.message);
            }
        }
        
        function compressJSON() {
            const input = inputEditor.getValue().trim();
            if (!input) {
                showError('请输入JSON数据');
                return;
            }
            
            try {
                const parsed = JSON.parse(input);
                const compressed = JSON.stringify(parsed);
                
                outputEditor.setValue(compressed);
                showSuccess('JSON压缩成功');
                hideError();
                updateStatistics();
            } catch (error) {
                showError('JSON格式错误: ' + error.message);
            }
        }
        
        function validateJSON() {
            const input = inputEditor.getValue().trim();
            if (!input) {
                showError('请输入JSON数据');
                return;
            }
            
            try {
                JSON.parse(input);
                showSuccess('JSON格式正确');
                hideError();
            } catch (error) {
                showError('JSON格式错误: ' + error.message);
            }
        }
        
        function autoValidate() {
            const input = inputEditor.getValue().trim();
            if (!input) {
                updateStatus('等待输入', 'gray');
                return;
            }
            
            try {
                JSON.parse(input);
                updateStatus('格式正确', 'green');
                hideError();
            } catch (error) {
                updateStatus('格式错误', 'red');
            }
        }
        
        function clearAll() {
            inputEditor.setValue('');
            outputEditor.setValue('');
            hideError();
            updateStatus('等待输入', 'gray');
            updateStatistics();
        }
        
        function copyToClipboard() {
            const output = outputEditor.getValue();
            if (!output) {
                alert('没有可复制的内容');
                return;
            }
            
            navigator.clipboard.writeText(output).then(() => {
                showSuccess('已复制到剪贴板');
            }).catch(() => {
                // 备用方案
                const textArea = document.createElement('textarea');
                textArea.value = output;
                document.body.appendChild(textArea);
                textArea.select();
                document.execCommand('copy');
                document.body.removeChild(textArea);
                showSuccess('已复制到剪贴板');
            });
        }
        
        function downloadJSON() {
            const output = outputEditor.getValue();
            if (!output) {
                alert('没有可下载的内容');
                return;
            }
            
            const blob = new Blob([output], { type: 'application/json' });
            const url = URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.href = url;
            link.download = 'formatted.json';
            link.click();
            URL.revokeObjectURL(url);
        }
        
        function loadSample() {
            const sampleJSON = {
                "name": "个人工具网站集",
                "version": "1.0.0",
                "description": "一个包含多种实用工具的网站",
                "tools": [
                    {
                        "id": 1,
                        "name": "PDF转图片",
                        "category": "文档处理",
                        "features": ["高质量转换", "批量处理", "多格式支持"]
                    },
                    {
                        "id": 2,
                        "name": "JSON格式化",
                        "category": "开发助手",
                        "features": ["语法高亮", "错误检测", "压缩美化"]
                    }
                ],
                "config": {
                    "theme": "light",
                    "language": "zh-CN",
                    "autoSave": true,
                    "settings": {
                        "maxFileSize": "10MB",
                        "allowedFormats": ["json", "txt"]
                    }
                }
            };
            
            inputEditor.setValue(JSON.stringify(sampleJSON, null, 2));
            updateStatistics();
            autoValidate();
        }
        
        function handleFileUpload(event) {
            const file = event.target.files[0];
            if (file) {
                const reader = new FileReader();
                reader.onload = function(e) {
                    inputEditor.setValue(e.target.result);
                    updateStatistics();
                    autoValidate();
                };
                reader.readAsText(file);
            }
        }
        
        function updateStatistics() {
            const input = inputEditor.getValue();
            const output = outputEditor.getValue();
            const content = output || input;
            
            // 字符数
            document.getElementById('charCount').textContent = content.length;
            
            // 行数
            document.getElementById('lineCount').textContent = content.split('\n').length;
            
            // 文件大小
            const bytes = new Blob([content]).size;
            document.getElementById('sizeInfo').textContent = formatBytes(bytes);
            
            // 嵌套深度
            try {
                if (content.trim()) {
                    const parsed = JSON.parse(content);
                    const depth = getMaxDepth(parsed);
                    document.getElementById('depthInfo').textContent = depth;
                } else {
                    document.getElementById('depthInfo').textContent = '0';
                }
            } catch {
                document.getElementById('depthInfo').textContent = '-';
            }
        }
        
        function formatBytes(bytes) {
            if (bytes === 0) return '0 B';
            const k = 1024;
            const sizes = ['B', 'KB', 'MB', 'GB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
        }
        
        function getMaxDepth(obj, depth = 1) {
            if (typeof obj !== 'object' || obj === null) {
                return depth;
            }
            
            let maxDepth = depth;
            for (const key in obj) {
                if (obj.hasOwnProperty(key)) {
                    const currentDepth = getMaxDepth(obj[key], depth + 1);
                    maxDepth = Math.max(maxDepth, currentDepth);
                }
            }
            
            return maxDepth;
        }
        
        function showError(message) {
            document.getElementById('errorMessage').textContent = message;
            document.getElementById('errorPanel').style.display = 'block';
        }
        
        function hideError() {
            document.getElementById('errorPanel').style.display = 'none';
        }
        
        function updateStatus(text, color) {
            const indicator = document.querySelector('#statusIndicator .w-3');
            const statusText = document.querySelector('#statusIndicator span');
            
            indicator.className = `w-3 h-3 rounded-full mr-2 bg-${color}-400`;
            statusText.textContent = text;
            statusText.className = `text-sm text-${color}-600`;
        }
        
        function showSuccess(message) {
            // 创建临时成功提示
            const successDiv = document.createElement('div');
            successDiv.className = 'fixed top-4 right-4 bg-green-500 text-white px-4 py-2 rounded-lg shadow-lg z-50';
            successDiv.innerHTML = `<i class="fas fa-check mr-2"></i>${message}`;
            
            document.body.appendChild(successDiv);
            
            setTimeout(() => {
                successDiv.remove();
            }, 3000);
        }
    </script>
</body>
</html>